
#include "modules/router.h"
#include "core/message.h"
#include "utils/diagnostic.h"

namespace mod {
	RouterModule::RouterModule(std::shared_ptr<Context> ctx, const string &module_name) : Module(ctx, module_name) {}
	bool RouterModule::Init() {
		// 创建套接字
		gateway_sockfd = create_udp_socket(ctx->config.Gateway.GatewayPort);
		if (gateway_sockfd < 0) {
			log_fatal("[Gateway] listener socket create failed.");
			return false;
		}

#if 0
		// 静态代理
		static_agent_sockfd = create_udp_socket(ctx->config.Gateway.StaticAgentPort);
		if (static_agent_sockfd < 0) {
			log_fatal("[StaticAgent] listener socket create failed.");
			return false;
		}

		// 动态代理
		dynamic_agent_sockfd = create_udp_socket(ctx->config.Gateway.DynamicAgentPort);
		if (dynamic_agent_sockfd < 0) {
			log_fatal("[DynamicAgent] listener socket create failed.");
			return false;
		}
		// auto sync = (SyncModule *) ctx->Mod(MODULE_SYNC);
#endif
		return true;
	}

	void RouterModule::Start() {
		if (this->gateway_sockfd < 0) {
			throw runtime_error("[Gateway] gateway socket fd invalid: " + to_string(gateway_sockfd));
		}

		// 添加监听器
		unique_ptr<Listener> gateway_listener = unique_ptr<Listener>(new Listener(gateway_sockfd, ctx->config.Gateway.GatewayPort, "Gateway"));
		gateway_listener->handler             = gateway_handler();
		ctx->addListener(move(gateway_listener));

#if 0
		if (this->static_agent_sockfd < 0) {
			throw runtime_error("[Gateway] static agent socket fd invalid: " + to_string(static_agent_sockfd));
		}

		// 添加监听器
		unique_ptr<Listener> static_agent_listener = unique_ptr<Listener>(new Listener(static_agent_sockfd, ctx->config.Gateway.StaticAgentPort, "StaticAgent "));
		static_agent_listener->handler             = static_agent_handler();
		ctx->addListener(move(static_agent_listener));


		if (this->dynamic_agent_sockfd < 0) {
			throw runtime_error("[Gateway] dynamic agent socket fd invalid: " + to_string(dynamic_agent_sockfd));
		}

		// 添加监听器
		unique_ptr<Listener> dynamic_agent_listener = unique_ptr<Listener>(new Listener(dynamic_agent_sockfd, ctx->config.Gateway.DynamicAgentPort, "DynamicAgent"));
		dynamic_agent_listener->handler             = dynamic_agent_handler();
		ctx->addListener(move(dynamic_agent_listener));
#endif
	}

	listen_handler RouterModule::gateway_handler() {
		return [this](int fd, const char *data, ssize_t len, const char *sender_ip, const ushort sender_port) {
			biz::Message msg;
			deserialize(&msg, (char *) data, (size_t) len);
			// 服务同步
			if (msg.magic == biz::SGW_SYNCHRO) {
				log_info("[Sync] [RCV] from %s:%d payload { %s } ", sender_ip, sender_port, msg.payload_data);
				auto si = ServiceInfo::decode(msg.payload_data);

				// 收到同步请求，发布同步事件，并被以下模块订阅：
				// 1. AgentModule/SyncModule： 根据情况创建客户端代理; 缓存本地化服务信息
				// 2. RegCenter： 	向本地注册中心注册服务
				ctx->eventBus.PublishAsync(SyncEvent{.service = si, .sender_ip = sender_ip, .sender_port = sender_port});
			} else if (msg.magic == biz::Msg_Type::SGW_REQUEST) {
				log_info("[Gateway] [REQ] from %s:%d payload { %.*s }", sender_ip, sender_port, msg.payload_len, msg.payload_data);
				Session           session;
				pair<int, ushort> fdport;

				// 根据报文中的路由信息(session_key)，查询会话状态。如果不存在会话数据，则创建本地会话信息。
				auto session_key = msg.routers[0].addr() + msg.routers[1].addr() + msg.routers[3].addr();
				bool exists      = ctx->GetSessionBytNat(session_key, session);
				if (!exists) {
					// 创建会话Socket
					fdport = create_udp_socket_dynamic();
					if (fdport.first < 1 || fdport.second < 1) {
						log_warn("[Session] Socket error, fd=%d port=%d", fdport.first, fdport.second);
						free_message(&msg);
						return;
					}

					// 服务回调/响应处理程序
					auto listener     = unique_ptr<Listener>(new Listener(fdport.first, fdport.second, "Session"));
					listener->handler = session_resp_handler(); // 响应  socketFD
					ctx->addListener(move(listener));

					// 创建代理服务
					session.sockFd = fdport.first;
					memcpy(session.routers, msg.routers, sizeof(msg.routers));
					session.routers[1] = createAddress(sender_ip, sender_port);
					session.serverAddr = create_addr(session.routers[3].port, session.routers[3].ip_str().c_str());

					// 保存会话信息
					ctx->SetSessionBytNat(session_key, session);
					ctx->SetSessionBytFd(fdport.first, session);
				}

				// 通过会话Socket将报文转发给Server
				auto    tar       = session.serverAddr;
				ssize_t sentBytes = sendto(session.sockFd, msg.payload_data, msg.payload_len, 0, (SOCKADDR *) &tar, sizeof(tar));
				if (sentBytes < 0) {
					log_error("[Session] Sent[FD:%d] error: %d", fd, errno);
				}

			} else if (msg.magic == biz::Msg_Type::API_PING) {
				ctx->eventBus.PublishAsync(PingEvent{.SockFd = fd, .SenderIp = sender_ip, .SenderPort = sender_port, .Result = "Pong"});
			} else {
				log_warn("[Gateway] Invalid magic");
			}
			free_message(&msg);
		};
	}

	// /// @brief 接收客户请求报文，根据ip:server_info哈希表，重新封装报文头,并转发给下一目标(网关)
	// listen_handler RouterModule::agent_handler() {
	// 	// 虚拟目标服务
	// 	return [this](int fd, const char *data, ssize_t len, const char *sender_ip, const ushort sender_port) {
	// 		log_info("[Agent] [REQ] from %s:%d payload { %.*s } ", sender_ip, sender_port, len, data);
	// 		NatMate ri;
	// 		auto    has = ctx->GetNatP2SMapper(fd, ri);
	// 		if (!has) {
	// 			log_warn("fd error,%d", fd);
	// 			return;
	// 		}

	// 		biz::Message msg = {.magic = biz::Msg_Type::SGW_REQUEST, .flag = 0};
	// 		msg.routers[0]   = createAddress(sender_ip, sender_port);               // 客户端
	// 		msg.routers[1]   = createAddress(ri.GatewayIP.c_str(), ri.GatewayPort); // Cli代理
	// 		msg.routers[3]   = createAddress(ri.ServiceIP.c_str(), ri.ServicePort); // 目标服务
	// 		// msg.hops         = 1;
	// 		msg.payload_len  = len; // 数据长度
	// 		msg.payload_data = (char *) malloc(msg.payload_len);
	// 		if (msg.payload_data == NULL) {
	// 			log_fatal("[Message] Malloc error: %d", errno);
	// 			free_message(&msg);
	// 			return;
	// 		}
	// 		memcpy(msg.payload_data, data, msg.payload_len);
	// 		auto tar = create_addr(ri.GatewayPort, ri.GatewayIP.c_str());

	// 		// 临时内存对象
	// 		size_t buffer_size = message_size(msg); // 消息长度
	// 		char  *buffer      = (char *) malloc(buffer_size);
	// 		serialize(&msg, buffer, buffer_size);

	// 		ssize_t sentBytes = sendto(fd, buffer, buffer_size, 0, (SOCKADDR *) &tar, sizeof(tar));
	// 		if (sentBytes < 0) {
	// 			log_error("[CliAgent] Sent[FD:%d] error: %d", fd, errno);
	// 		}
	// 		free(buffer);
	// 		free_message(&msg);
	// 	};
	// }

	DIAGNOSTIC_PUSH
	IGNORE_UNUSED_PARAMETER
	listen_handler RouterModule::static_agent_handler() {
		// 接收客户端请求
		// 根据ip:server哈希表，重新封装报文头
		return [](int fd, const char *data, ssize_t len, const char *sender_ip, const ushort sender_port) {};
	}
	DIAGNOSTIC_POP

	/// @brief Session接收来自Server消息,并处理程序
	/// @return
	listen_handler RouterModule::session_resp_handler() {
		// 接收客户端请求
		// 根据ip:server哈希表，重新封装报文头
		return [this](int fd, const char *data, ssize_t len, const char *sender_ip, const ushort sender_port) {
			Session session;
			auto    has = ctx->GetSessionByFd(fd, session);
			if (!has) {
				log_error("[Session] Response[FD:%d] session error: %d", fd, errno);
				return;
			}

			auto    agt       = session.routers[0];
			auto    tar       = create_addr(agt.port, agt.ip_str().c_str());
			ssize_t sentBytes = sendto(session.sockFd, data, len, 0, (SOCKADDR *) &tar, sizeof(tar));
			if (sentBytes < 0) {
				log_error("[Session] Response [FD:%d] error: %d", fd, errno);
				return;
			}
			log_info("[Session] [FD:%d] Response(%d) to %s payload { %.*s } ...", session.sockFd, sentBytes, agt.addr().c_str(), len, data);
		};
	}

	void RouterModule::Stop() {}

	RouterModule::~RouterModule() {
		// 释放资源
		ctx->removeByFd(gateway_sockfd);
		ctx->removeByFd(static_agent_sockfd);
		// ctx->removeByFd(dynamic_agent_sockfd);
	}
} // namespace mod
